              package com.java.diagnostics.visualizer.parser.vgc.converters;
              
              import com.java.diagnostics.visualizer.data.DataPoint;
              import com.java.diagnostics.visualizer.impl.axes.AbstractUnitConverter;
              import com.java.diagnostics.visualizer.impl.axes.NonLinearConverter;
              import java.text.MessageFormat;
              import java.util.Arrays;
              import java.util.Set;
              import java.util.SortedMap;
              import java.util.TreeMap;
              
              public abstract class MapUnitConverter extends AbstractUnitConverter
                implements NonLinearConverter
              {
                private SortedMap mappings;
                private Double[] keyArray = null;
              
                protected double UNSET = -1.0D;
              
                protected MapUnitConverter() {
                  this.mappings = new TreeMap();
                }
              
                public void addPoint(int sequenceNumber, double entry) {
                  synchronized (this.mappings) {
                    this.mappings.put(new Double(sequenceNumber), new Double(entry));
                    this.keyArray = null;
                  }
                }
              
                public double convert(double number)
                {
                  return this.UNSET;
                }
              
                public double convert(DataPoint dataPoint) {
                  synchronized (this.mappings) {
                    return getFromMap(this.mappings, dataPoint.getSequenceUID());
                  }
                }
              
                public String format(DataPoint dataPoint) {
                  synchronized (this.mappings) {
                    return formatUnconverted(getFromMap(this.mappings, dataPoint.getSequenceUID()));
                  }
                }
              
                public final String formatWithUnits(DataPoint dataPoint)
                {
                  return MessageFormat.format(getFormatWithUnitsPattern(), new Object[] { format(dataPoint), getUnitName() });
                }
              
                private double getFromMap(SortedMap map, int key) {
                  Object entry = this.mappings.get(new Double(key));
                  if (entry != null) {
                    return ((Double)entry).doubleValue();
                  }
              
                  return binarySearch(key, map);
                }
              
                private double binarySearch(int key, SortedMap map)
                {
	          //added by wenguang.huang 2014年4月25日 下午12:13:14
               if(map.size()==0)
  	            return 0;
			  //added end by wenguang.huang 2014年4月25日 下午12:13:14



                  if (this.keyArray == null) {
                    this.keyArray = ((Double[])map.keySet().toArray(new Double[0]));
                  }
              
                  Double doubleKey = new Double(key);
                  int foundIndex = Arrays.binarySearch(this.keyArray, doubleKey);
                  foundIndex = Math.abs(foundIndex) - 1;
              
                  if (foundIndex >= map.size()) {
                    return ((Double)map.get(new Double(
                      ((Double)map.lastKey()).doubleValue()))).doubleValue();
                  }
              
                  double check = this.keyArray[foundIndex].doubleValue();
                  Double secondValue = null;
                  SortedMap newMap = new TreeMap();
                  newMap.put(Double.valueOf(check), (Double)map.get(Double.valueOf(check)));
              
                  if (key > check) {
                    double oneAfterCheck = this.keyArray[(foundIndex + 1)].doubleValue();
                    secondValue = (Double)map.get(Double.valueOf(oneAfterCheck));
                    newMap.put(Double.valueOf(oneAfterCheck), secondValue);
                  } else {
                    if (foundIndex == 0) {
                      return ((Double)map.get(new Double(
                        ((Double)map.firstKey()).doubleValue()))).doubleValue();
                    }
                    double oneBeforeCheck = this.keyArray[(foundIndex - 1)].doubleValue();
                    secondValue = (Double)map.get(Double.valueOf(oneBeforeCheck));
                    newMap.put(Double.valueOf(oneBeforeCheck), secondValue);
                  }
                  return interpolateInSmallMap(newMap, key);
                }
              
                protected double interpolateInSmallMap(SortedMap map, int key) {
                  double floor = ((Double)map.firstKey()).doubleValue();
                  double ceiling = ((Double)map.lastKey()).doubleValue();
              
                  if (ceiling == floor) {
                    return ((Double)map.get(new Double(floor))).doubleValue();
                  }
              
                  if ((key < ceiling) && (key > floor)) {
                    Double lowValueObject = (Double)map.get(new Double(
                      floor));
                    double lowValue = lowValueObject.doubleValue();
                    double highValue = ((Double)map.get(new Double(ceiling)))
                      .doubleValue();
              
                    double fraction = (key - floor) / (ceiling - floor);
                    double value = fraction * (highValue - lowValue) + lowValue;
                    return value;
                  }if (key > ceiling)
                  {
                    Double lowValueObject = (Double)map.get(new Double(
                      floor));
                    double lowValue = lowValueObject.doubleValue();
                    double highValue = ((Double)map.get(new Double(ceiling)))
                      .doubleValue();
              
                    double fraction = (key - ceiling) / (ceiling - floor);
              
                    double value = fraction * (highValue - lowValue) + highValue;
                    return value;
                  }
              
                  Double lowValueObject = (Double)map.get(new Double(
                    floor));
                  double lowValue = lowValueObject.doubleValue();
                  double highValue = ((Double)map.get(new Double(ceiling)))
                    .doubleValue();
                  double ceilingDelta = 1.0D - (ceiling - key) / (
                    ceiling - floor);
                  double floorDelta = 1.0D - (key - floor) / (
                    ceiling - floor);
              
                  double value = lowValue * floorDelta + highValue * 
                    ceilingDelta;
                  return value;
                }
              }

